/**
 * Copyright (C) 2017 北京市太极华青信息系统有限公司
 *
 * @version v1.0
 * @date 2017年12月22日 下午1:37:44
 */
package avicit.bdp.lineage.druid.util;

import cn.hutool.core.lang.ClassScanner;
import org.apache.commons.lang3.StringUtils;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 类扫描工具
 *
 *
 */

public class ClassPathScaner {

    private String basePackage = "java.lang";

    private String subPackage = "";

    private List<String> basePackages = new ArrayList<String>();

    ;

    /**
     * 路径扫描构造函数
     *
     * @param basePackage 扫描的包名
     */
    public ClassPathScaner(String basePackage) {
        super();
        this.basePackage = basePackage;
    }

    public ClassPathScaner(List<String> basePackages) {
        this.basePackages = basePackages;
    }


    /**
     * 开始扫描，依赖于Spring,asm等第三方包,注意如果是把代码打包到jar中后，<br/>
     * 打包时注意选择Add directory entries方式，否则是扫描不到的。
     *
     * @return 返回包中所包含的类Class
     * @throws Exception
     */
    @SuppressWarnings({"unchecked"})
    public List<Class> scanPackageWithSpring() throws Exception {

        List<Class> clazzes = new ArrayList<Class>();

        if (basePackages == null || basePackages.size() == 0) {
            basePackages = new ArrayList<String>();
            basePackages.add(basePackage);
        }
        if (basePackages.size() > 0) {
            for (String bpk : basePackages) {
                ClassScanner scanner = new ClassScanner(bpk);
                Set<Class<?>> bpkList = scanner.scan();
                for (Class clazz : bpkList) {
                    clazzes.add(clazz);
                }
            }

        }
        return clazzes;
    }

    /**
     * 查找实现特定annotation的类
     *
     * @param annotation
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public List<Class> findAnnotationClazz(Class annotation) throws Exception {
        List<Class> clazz = new ArrayList<Class>();
        List<Class> allClazz = scanPackageWithSpring();
        for (Class c : allClazz) {
            for (Annotation a : c.getAnnotations()) {
                if (a.annotationType() == annotation) {
                    clazz.add(c);
                }
            }
        }
        return clazz;
    }

    /**
     * 获取某下类指定注释指定属性的属性值
     *
     * @param clazz
     * @param annotation
     * @param propertie
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public static String findClazzByAnnotationValue(Class clazz, Class annotation, String propertie) throws Exception {
        for (Annotation ano : clazz.getAnnotations()) {
            if (ano.annotationType() == annotation) {
                return ano.getClass().getMethod(propertie).invoke(ano).toString();
            }
        }
        return null;
    }

    /**
     * 查找实现特定interface的类
     *
     * @param interfaceCalss
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public List<Class> findInterfaceClazz(Class interfaceCalss) throws Exception {
        List<Class> clazz = new ArrayList<Class>();
        List<Class> allClazz = scanPackageWithSpring();
        for (Class c : allClazz) {
            for (Class a : c.getInterfaces()) {
                if (a == interfaceCalss) {
                    clazz.add(c);
                }
            }
        }
        return clazz;
    }

    @SuppressWarnings("unchecked")
    public List<Class> findBySuperClass(Class superClass) throws Exception {
        List<Class> clazz = new ArrayList<Class>();
        List<Class> allClazz = scanPackageWithSpring();
        for (Class c : allClazz) {
            Class superCls = c.getSuperclass();
            while (superCls != null && superCls != Object.class) {
                if (superCls == superClass) {
                    clazz.add(c);
                    break;
                }
                superCls = superCls.getSuperclass();
            }
        }
        return clazz;
    }

    /**
     * 获取接口所在的包名列表
     *
     * @param superClass
     * @return
     * @throws Exception
     * @version v1.0
     * @date 2017年12月22日 下午2:22:42
     */
    public String findPackageBySuperIntefaces(Class superClass) throws Exception {
        List<String> clazz = new ArrayList<String>();
        Map<String, String> map = new HashMap<String, String>();
        List<Class> allClazz = scanPackageWithSpring();
        for (Class c : allClazz) {
            Class[] superCls = c.getInterfaces();

            for (Class superInter : superCls) {
                if (superInter == superClass) {
                    String pack = c.getPackage().getName();
                    map.put(pack, pack);
                    break;
                }

            }

        }
        clazz.addAll(map.keySet());
        return StringUtils.join(clazz, ",");
    }

    /**
     * 获取父类的所有子类
     *
     * @param superClass
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public List<Class> findSubClass(Class superClass) throws Exception {
        List<Class> clazz = new ArrayList<Class>();
        List<Class> allClazz = scanPackageWithSpring();
        for (Class c : allClazz) {
            if (c.getSuperclass() == superClass) {
                clazz.add(c);
            }
        }
        return clazz;
    }

}
